/**
 **********************************************************************************************************************
 * @file    cot_task.c
 * @brief   该文件提供任务时间片论任务调度功能
 *
 * @details  功能详细说明：
 *           + 任务调度初始化：初始化任务管理器，包括普通任务和中断任务的管理
 *           + 任务调度功能启动：启动调度系统，进入循环调度模式
 *           + 任务创建与销毁：支持动态创建和销毁任务
 *           + 优先级管理：支持任务优先级设置，范围5-250
 *           + 时间片轮转：基于1ms定时器中断的时间片轮转调度
 *           + 系统监控：支持CPU负载率监控和系统运行时间统计
 *
 **********************************************************************************************************************
 *
 * 使用方式:
 *    1. 使用前初始化函数 cotTask_Init
 *    2. 使用 1ms 定时器中断调用 cotTask_Remarks
 *    3. 主函数调用 cotTask_Start 启动任务调度, 函数不会退出
 *    4. 通过 cotTask_Creat 添加普通任务
 *    5. 通过 cotTask_IsrCreat 添加中断任务
 *    6. 可通过 cotTask_GetLoadRate 监控系统负载
 *    7. 可通过 cotTask_GetSysTimer 获取系统运行时间
 *
 * 注意事项：
 *    1. 每个任务函数不能被阻塞，尽量保证任务执行的时间小于 1ms
 *    2. 调度周期必须大于调度函数任务耗时
 *    3. 中断任务应当尽可能简短，避免影响系统实时性
 *    4. 任务优先级设置应当合理，避免低优先级任务得不到执行机会
 *
 **********************************************************************************************************************
 */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "./SYSTEM/Task/cot_task.h"
#include "./SYSTEM/Task/cot_task_cfg.h"
#include <stdbool.h>
#include <stddef.h>

/* Private typedef ---------------------------------------------------------------------------------------------------*/

/**
 * @brief 普通调度任务信息结构体定义
 */
typedef struct
{
    bool isUsed;           /* 标记任务是否被使用，true-使用中，false-未使用 */
    bool isRunnig;         /* 标记任务是否在运行，true-运行中，false-未运行 */
    uint8_t priority;      /* 任务优先级，范围5-250，值越小优先级越高 */
    uint16_t timer;        /* 任务计时器，用于控制任务执行周期 */
    uint16_t itvTime;      /* 任务执行间隔时间，单位ms */
    TaskRunCB pfnTaskHook; /* 任务函数指针，指向具体的任务处理函数 */
} TaskInfo_t;              /* 普通任务信息结构体，用于主循环中调度 */
/**
 * @brief 任务信息结构体定义
 */
typedef struct
{
    uint16_t timer;        /* 中断任务计时器，用于控制任务执行周期 */
    uint16_t itvTime;      /* 中断任务执行间隔时间，单位ms */
    TaskRunCB pfnTaskHook; /* 中断任务函数指针，指向具体的中断处理函数 */
} IsrTaskInfo_t;           /* 中断任务信息结构体，用于中断中调度 */

typedef struct
{
#ifdef COT_CTASK_USE_LOAD_RATE
    uint8_t mcuLoadRate;          /* CPU负载率，范围0-100%，表示系统繁忙程度 */
    uint16_t idleTaskExpectedCnt; /* 空闲任务预期执行次数，用于负载率计算 */
    uint16_t idleTaskActualCnt;   /* 空闲任务实际执行次数，用于负载率计算 */
#endif
    bool isStart;                                    /* 调度系统启动标志，true-已启动，false-未启动 */
    uint32_t systimer;                               /* 系统计时器，记录系统运行时间，单位ms */
    TaskInfo_t task[COT_TASK_SUPPORT_NUM];           /* 普通任务数组，存储所有主循环任务 */
    IsrTaskInfo_t isrTask[COT_TASK_ISR_SUPPORT_NUM]; /* 中断任务数组，存储所有中断任务 */
} TaskManage_t;                                      /* 任务管理结构体，管理所有任务的运行状态 */

/* Private define ----------------------------------------------------------------------------------------------------*/
/* Private macro -----------------------------------------------------------------------------------------------------*/
/* Private variables -------------------------------------------------------------------------------------------------*/

static TaskManage_t sg_tTaskManage;

/* Private function prototypes ---------------------------------------------------------------------------------------*/
#ifdef COT_CTASK_USE_LOAD_RATE
static void __IdleTask(void);
static void __IdleIsrTask(void);
#endif
/* Private function --------------------------------------------------------------------------------------------------*/

#ifdef COT_CTASK_USE_LOAD_RATE
/**
 * @brief      空闲任务
 * @details    用于计算系统负载的普通任务，每执行一次增加实际执行计数器
 */
static void __IdleTask(void)
{
    sg_tTaskManage.idleTaskActualCnt++;
}

/**
 * @brief      空闲中断任务
 * @details    用于计算系统负载的中断任务，每执行一次增加预期执行计数器并计算负载率
 */
static void __IdleIsrTask(void)
{
    sg_tTaskManage.idleTaskExpectedCnt++;

    if (sg_tTaskManage.idleTaskExpectedCnt >= 1000)
    {
        sg_tTaskManage.mcuLoadRate = 100 - (sg_tTaskManage.idleTaskActualCnt * 100 / sg_tTaskManage.idleTaskExpectedCnt);
        sg_tTaskManage.idleTaskExpectedCnt = 0;
        sg_tTaskManage.idleTaskActualCnt = 0;
    }
}
#endif

/**
 * @brief      任务调度初始化
 * @details    初始化任务管理器，包括普通任务和中断任务的管理数据结构
 *
 * @note       必须在使用任务系统前调用此函数
 * @retval     无
 */
void cotTask_Init(void)
{
    int i;

    /* 初始化任务管理器的基本状态 */
    sg_tTaskManage.isStart = false; /* 初始状态为未启动 */
    sg_tTaskManage.systimer = 0;    /* 系统计时器清零 */

#ifdef COT_CTASK_USE_LOAD_RATE
    /* 初始化负载率相关参数 */
    sg_tTaskManage.mcuLoadRate = 0;
    sg_tTaskManage.idleTaskActualCnt = 0;
    sg_tTaskManage.idleTaskExpectedCnt = 0;
#endif

    /* 初始化所有普通任务槽 */
    for (i = 0; i < COT_TASK_SUPPORT_NUM; i++)
    {
        sg_tTaskManage.task[i].isUsed = false;     /* 标记为未使用 */
        sg_tTaskManage.task[i].isRunnig = false;   /* 标记为未运行 */
        sg_tTaskManage.task[i].itvTime = 0;        /* 清零执行间隔 */
        sg_tTaskManage.task[i].pfnTaskHook = NULL; /* 清空任务函数 */
        sg_tTaskManage.task[i].timer = 0;          /* 清零计时器 */
        sg_tTaskManage.task[i].priority = 255;     /* 设置最低优先级 */
    }

    /* 初始化所有中断任务槽 */
    for (i = 0; i < COT_TASK_ISR_SUPPORT_NUM; i++)
    {
        sg_tTaskManage.isrTask[i].itvTime = 0;        /* 清零执行间隔 */
        sg_tTaskManage.isrTask[i].pfnTaskHook = NULL; /* 清空任务函数 */
        sg_tTaskManage.isrTask[i].timer = 0;          /* 清零计时器 */
    }

#ifdef COT_CTASK_USE_LOAD_RATE
    /* 创建系统负载监测任务 */
    cotTask_Creat(__IdleTask, 1, 255);  /* 创建空闲任务，最低优先级 */
    cotTask_IsrCreat(__IdleIsrTask, 1); /* 创建空闲中断任务，1ms周期 */
#endif
}

/**
 * @brief      创建新的任务调度
 * @details    创建一个新的普通任务，并根据优先级插入到任务队列中
 *
 * @param[in]  pfnTask 回调任务函数，指向具体的任务处理函数
 * @param[in]  time    调度周期，单位ms，指定任务执行的时间间隔
 * @param[in]  priority 调度优先级，范围5-250
 *             @arg     5-250 值越小，优先级越高
 *
 * @note       任务函数不能被阻塞，尽量保证任务执行的时间小于 1ms，且调度周期一定要大于调度函数任务耗时
 * @retval     无
 */
void cotTask_Creat(TaskRunCB pfnTask, uint16_t time, uint8_t priority)
{
    int i, j;

    /* 确保优先级在有效范围内 */
    if (priority < 5)
    {
        priority = 5; /* 最高优先级为5 */
    }

    if (priority > 250)
    {
        priority = 250; /* 最低优先级为250 */
    }

    /* 查找合适的任务槽位 */
    for (i = 0; i < COT_TASK_SUPPORT_NUM; i++)
    {
        /* 跳过优先级更高的任务 */
        if (sg_tTaskManage.task[i].priority < priority)
        {
            continue;
        }

        /* 如果当前槽位已被使用，需要移动现有任务 */
        if (sg_tTaskManage.task[i].isUsed)
        {
            /* 将现有任务向后移动，为新任务腾出位置 */
            for (j = COT_TASK_SUPPORT_NUM - 1; j > i; j--)
            {
                sg_tTaskManage.task[j] = sg_tTaskManage.task[j - 1];
                sg_tTaskManage.task[j - 1].isUsed = false;
            }
        }

        /* 配置新任务参数 */
        sg_tTaskManage.task[i].isUsed = true;         /* 标记为已使用 */
        sg_tTaskManage.task[i].isRunnig = false;      /* 初始状态为未运行 */
        sg_tTaskManage.task[i].itvTime = time;        /* 设置执行周期 */
        sg_tTaskManage.task[i].pfnTaskHook = pfnTask; /* 设置任务函数 */
        sg_tTaskManage.task[i].timer = time;          /* 初始化计时器 */
        sg_tTaskManage.task[i].priority = priority;   /* 设置优先级 */
        break;
    }
}

/**
 * @brief      销毁任务
 * @details    从任务队列中移除指定的普通任务
 *
 * @param[in]  pfnTask 回调任务函数，要销毁的任务函数指针
 *
 * @note       如果找不到指定的任务，不会有任何操作
 * @retval     无
 */
void cotTask_Destory(TaskRunCB pfnTask)
{
    int i;

    /* 遍历查找要销毁的任务 */
    for (i = 0; i < COT_TASK_SUPPORT_NUM; i++)
    {
        if (sg_tTaskManage.task[i].pfnTaskHook == pfnTask)
        {
            sg_tTaskManage.task[i].isUsed = false; /* 标记任务为未使用状态 */
            break;
        }
    }
}

/**
 * @brief      创建新的中断任务调度
 * @details    创建一个在中断中执行的任务
 *
 * @param[in]  pfnTask 回调任务函数，指向具体的中断任务处理函数
 * @param[in]  time    调度周期，单位ms，指定中断任务执行的时间间隔
 *
 * @note       由于采用的是中断方式，中断任务函数不能被阻塞，必须保证任务耗时极短；适用于要求极高且耗时极短的任务
 * @retval     无
 */
void cotTask_IsrCreat(TaskRunCB pfnTask, uint16_t time)
{
    int i;

    /* 查找空闲的中断任务槽 */
    for (i = 0; i < COT_TASK_ISR_SUPPORT_NUM; i++)
    {
        if (sg_tTaskManage.isrTask[i].pfnTaskHook == NULL)
        {
            /* 配置新的中断任务 */
            sg_tTaskManage.isrTask[i].itvTime = time;        /* 设置执行周期 */
            sg_tTaskManage.isrTask[i].pfnTaskHook = pfnTask; /* 设置任务函数 */
            sg_tTaskManage.isrTask[i].timer = time;          /* 初始化计时器 */
            break;
        }
    }
}

/**
 * @brief      销毁中断任务
 * @details    从中断任务队列中移除指定的中断任务
 *
 * @param[in]  pfnTask 回调任务函数，要销毁的中断任务函数指针
 *
 * @note       如果找不到指定的任务，不会有任何操作
 * @retval     无
 */
void cotTask_IsrDestory(TaskRunCB pfnTask)
{
    int i, j;

    /* 遍历查找要销毁的中断任务 */
    for (i = 0; i < COT_TASK_ISR_SUPPORT_NUM; i++)
    {
        if (sg_tTaskManage.isrTask[i].pfnTaskHook == pfnTask)
        {
            sg_tTaskManage.isrTask[i].pfnTaskHook = NULL; /* 清空任务函数指针 */

            /* 移动后续任务，填补空缺 */
            for (j = i; j < COT_TASK_ISR_SUPPORT_NUM - 1; j++)
            {
                sg_tTaskManage.isrTask[j] = sg_tTaskManage.isrTask[j + 1];
            }
            break;
        }
    }
}

/**
 * @brief      执行任务调度函数
 * @details    遍历所有任务，执行需要运行的最高优先级任务
 *
 * @note       每次调用只会执行一个最高优先级的可运行任务
 * @retval     无
 */
static void __TaskScheduling(void)
{
    uint8_t idx = 0;

    /* 遍历所有任务，执行需要运行的任务 */
    while (idx < COT_TASK_SUPPORT_NUM && sg_tTaskManage.task[idx].pfnTaskHook != NULL)
    {
        /* 检查任务是否需要执行 */
        if (sg_tTaskManage.task[idx].isUsed && sg_tTaskManage.task[idx].isRunnig)
        {
            sg_tTaskManage.task[idx].pfnTaskHook();    /* 执行任务函数 */
            sg_tTaskManage.task[idx].isRunnig = false; /* 清除运行标志 */
            break;                                     /* 每次只执行一个任务 */
        }
        idx++;
    }
}

/**
 * @brief      任务启动
 * @details    启动任务调度系统，进入无限循环模式执行任务
 *
 * @note       该函数调用后不会返回
 * @retval     无
 */
void cotTask_Start(void)
{
    sg_tTaskManage.isStart = true; /* 设置启动标志 */

    /* 进入任务调度循环 */
    while (1)
    {
        __TaskScheduling(); /* 循环执行任务调度 */
    }
}

/**
 * @brief      任务调度状态管理
 * @details    处理任务计时器更新和中断任务执行
 *
 * @note       需要在1ms定时器中断中调用
 * @retval     无
 */
void cotTask_Remarks(void)
{
    uint8_t idx = 0;

    /* 检查系统是否已启动 */
    if (!sg_tTaskManage.isStart)
    {
        return;
    }

    sg_tTaskManage.systimer++; /* 系统时间计数递增 */

    /* 更新普通任务的计时器状态 */
    while (idx < COT_TASK_SUPPORT_NUM && sg_tTaskManage.task[idx].pfnTaskHook != NULL)
    {
        if (sg_tTaskManage.task[idx].isUsed)
        {
            if (sg_tTaskManage.task[idx].timer)
            {
                sg_tTaskManage.task[idx].timer--; /* 任务计时器递减 */

                /* 检查是否到达执行时间 */
                if (sg_tTaskManage.task[idx].timer == 0)
                {
                    /* 重置计时器并标记任务可运行 */
                    sg_tTaskManage.task[idx].timer = sg_tTaskManage.task[idx].itvTime;
                    sg_tTaskManage.task[idx].isRunnig = true;
                }
            }
        }
        idx++;
    }

    /* 更新中断任务的计时器状态 */
    idx = 0;
    while (idx < COT_TASK_ISR_SUPPORT_NUM && sg_tTaskManage.isrTask[idx].pfnTaskHook != NULL)
    {
        if (sg_tTaskManage.isrTask[idx].timer)
        {
            sg_tTaskManage.isrTask[idx].timer--; /* 中断任务计时器递减 */

            /* 检查是否到达执行时间 */
            if (sg_tTaskManage.isrTask[idx].timer == 0)
            {
                /* 重置计时器并直接执行中断任务 */
                sg_tTaskManage.isrTask[idx].timer = sg_tTaskManage.isrTask[idx].itvTime;
                sg_tTaskManage.isrTask[idx].pfnTaskHook();
            }
        }
        idx++;
    }
}

#ifdef COT_CTASK_USE_LOAD_RATE
/**
 * @brief      获取 MCU 负载率
 * @details    返回当前系统CPU负载百分比
 *
 * @note       通过该函数得到 MCU 负载率，负载率越大，实时性和响应性越差
 * @retval     MCU 负载率，范围0-100%
 */
uint8_t cotTask_GetLoadRate(void)
{
    return sg_tTaskManage.mcuLoadRate; /* 返回当前系统CPU负载率 */
}
#endif

/**
 * @brief      获取系统计时
 * @details    返回系统从启动以来运行的毫秒数
 *
 * @note       需等启动后才开始计时
 * @retval     系统运行时间，单位ms
 */
uint32_t cotTask_GetSysTimer(void)
{
    return sg_tTaskManage.systimer; /* 返回系统运行的总毫秒数 */
}
